/**
 * Gripper is a small window part that makes a window resizeable.
 * When the user drags a gripper, the window will be resized.
 *
 * @author Andrey Anisimov <hercules@inbox.ru>
 * @see core.ui.Handle
 */

import core.ui.Window;
import core.util.Listeners;

class Gripper extends Window {

	this.Gripper = function(parent, x, y, width, height) {
		super(parent, x, y, width, height);
		this.resizeinfo = {};
		this.direction = (Gripper.SOUTH | Gripper.EAST);
		this.listeners = new Listeners([
            'onBeginResize',
            'onEndResize',
            'onResize'
        ]);
	}

	this.addResizeListener = function(listener) {
		this.listeners.add(listener);
	}

	this.removeResizeListener = function(listener) {
		this.listeners.remove(listener);
	}

	/**
	 * Sets the window to be resized when user drags this gripper.
	 *
	 * @param target (Window) target window.
	 * @param minWidth		(int) [optional] The minimum target width
	 * @param minHeight	(int) [optional] The minimum target height
	 * @param maxWidth		(int) [optional] The maximum target width
	 * @param maxHeight	(int) [optional] The maximum target height
	 */
	this.setResizeWindow = function(wnd, minWidth, minHeight, maxWidth, maxHeight) {
		this.target = wnd;
		this.resizeinfo.minWidth = minWidth;
		this.resizeinfo.minHeight = minHeight;
		this.resizeinfo.maxWidth = maxWidth;
		this.resizeinfo.maxHeight = maxHeight;
	}
	
	/**
	 * Gets the current resize target window.
	 *
	 * @return Window
	 */
	this.getResizeWindow = function() {
		return this.target;
	}
	
	/**
	 * Sets the resizing direction.
	 * The direction is a bitwise combination of the following:
	 * Gripper.NORTH
 	 * Gripper.SOUTH
 	 * Gripper.EAST
 	 * Gripper.WEST
	 * 
	 * @param dir (int) The resizing direction.
	 */
	this.setDirection = function(dir) {
		this.direction = dir;
		// Set cursor
		var c = '';
		if (this.direction & Gripper.SOUTH) {
			c += 's';
		} else if (this.direction & Gripper.NORTH) {
			c += 'n';
		}
		if (this.direction & Gripper.WEST) {
			c += 'w';
		} else if (this.direction & Gripper.EAST) {
			c += 'e';
		}
		this.setStyle('cursor', c + '-resize');
	}

	/**
	 * Inits resizing state.
	 * 
	 * @param x, y (int) start resize coords
	 */
	this.beginResize = function(event) {
		this.resizeinfo.resizeState = true;
		this.resizeinfo.x = event.getScreenX();
		this.resizeinfo.y = event.getScreenY();
		this.attachGlobalEvent('mouseup');
		this.attachGlobalEvent('mousemove');
	}

	/**
	 * Finishes resizing state. 
	 */
	this.endResize = function() {
		this.detachGlobalEvent('mouseup');
		this.detachGlobalEvent('mousemove');
		this.resizeinfo.resizeState = false;
	}
	
	/**
	 * Checks whether the gripper is in resizing state.
	 *
	 * @return bool
	 */
	this.isResizing = function() {
		return this.resizeinfo.resizeState;
	}
	
	this.close = function() {
		if (this.isResizing()) {
			this.endResize();
		}
		super.close();
	}

	/**
	 * @protected
	 */
	this.fireBeginResize = function() {
		this.listeners.call('onBeginResize', [this]);
	}

	/**
	 * @protected
	 */
	this.fireEndResize = function() {
		this.listeners.call('onEndResize', [this]);
	}

	/**
	 * @protected
	 * @param dx
	 * @param dy
	 */
	this.fireResize = function(dx, dy) {
		this.listeners.call('onResize', [this, dx, dy]);
	}

	this.onmousedown = function(event) {
		this.beginResize(event);
		this.fireBeginResize();
		event.stop();
	}
	
	this.onmousemove = function(event) {
		if (this.isResizing()) {
			// Get offset
			var dx = (event.getScreenX() - this.resizeinfo.x);
			var dy = (event.getScreenY() - this.resizeinfo.y);
			
			// Apply directions filter
			dx *= ((this.direction & Gripper.EAST) || (this.direction & Gripper.WEST) ? 1 : 0);
			dy *= ((this.direction & Gripper.NORTH) || (this.direction & Gripper.SOUTH) ? 1 : 0);
			
			// Resize target window
			var left = this.target.getX();
			var top = this.target.getY();
			var width = this.target.getWidth();
			var height = this.target.getHeight();
			
			if (this.direction & Gripper.WEST) {
				left += dx;
				width += -dx;
			} else {
				width += dx;
			}
			if (this.direction & Gripper.NORTH) {
				top += dy;
				height += -dy;
			} else {
				height += dy;
			}
			
			// Limit resizing
			if (this.resizeinfo.minWidth && (width < this.resizeinfo.minWidth)) {
				width = this.resizeinfo.minWidth;
				left = this.target.getX();
			}
			if (this.resizeinfo.minHeight && (height < this.resizeinfo.minHeight)) {
				height = this.resizeinfo.minHeight;
				top = this.target.getY();
			}
			if (this.resizeinfo.maxWidth && (width > this.resizeinfo.maxWidth)) {
				width = this.resizeinfo.maxWidth;
				left = this.target.getX();
			}
			if (this.resizeinfo.maxHeight && (height > this.resizeinfo.maxHeight)) {
				height = this.resizeinfo.maxHeight;
				top = this.target.getY();
			}
			
			this.target.move(left, top);
			this.target.resize(width, height);
			this.resizeinfo.x = event.getScreenX();
			this.resizeinfo.y = event.getScreenY();
			event.stop();
			
			this.fireResize(dx, dy);
		}
	}

	this.onmouseup = function(event) {
		if (this.isResizing()) {
			this.endResize();
			this.fireEndResize();
			event.stop();
		}
	}
}

core.ui.Gripper.NORTH = 0x0001;
core.ui.Gripper.SOUTH = 0x0004;
core.ui.Gripper.EAST = 0x0008;
core.ui.Gripper.WEST = 0x0010;